package com.shangxia.monomer.study.thread.threadPool;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.shangxia.monomer.study.designPatterns.creationType.factory.base.Apple;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author zhouya38158
 * @Package com.shangxia.monomer.study.thread.threadPool
 * @date 2021/7/21 10:21
 */
public class CreateThreadPool {
    /**
     * CallerRunsPolicy 交给 主线程 继续执行
     */
    private static final ExecutorService executorsRun =
            new ThreadPoolExecutor(2, 3,
                    20L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(5),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    /**
     * AbortPolicy 抛出异常，后续停止执行
     */
    private static final ExecutorService executorsAbort =
            new ThreadPoolExecutor(5, 10,
                    20L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(20),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy());
    /**
     * DiscardOldestPolicy 拒绝新进来的
     */
    private static final ExecutorService executorsDiscardOld =
            new ThreadPoolExecutor(2, 3,
                    20L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(5),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.DiscardOldestPolicy());

    /**
     * DiscardOldestPolicy 拒绝后进来的
     */
    private static final ExecutorService executorsDiscard =
            new ThreadPoolExecutor(2, 3,
                    20L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(5),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.DiscardPolicy());

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("testCallableTask start");
        Long start = System.currentTimeMillis();
        testPolicy();
        System.out.println("testCallableTask end");
        System.out.println("testCallableTask 耗时" + (System.currentTimeMillis() - start) + "ms");

    }

    /**
     * 先创建任务，在一次性执行
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void testCallableTaskALL() throws InterruptedException, ExecutionException {
        List<Task> futureTasks = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Task task = new Task("" + i, new Date(), new Apple());
            futureTasks.add(task);
        }
        List<Future<Result>> futures = executorsRun.invokeAll(futureTasks);
        for (Future<Result> future : futures) {
            Result result = future.get();
            System.out.println(result.getMsgCode());
        }
        futureTasks.clear();
    }

    /**
     * 创建一个执行一个
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void testCallableTask() throws InterruptedException, ExecutionException {
        List<Future> futures = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            FutureTask<Result> resultFutureTask = new FutureTask<>(new Task("" + i, new Date(), new Apple()));
            executorsRun.submit(resultFutureTask);
            futures.add(resultFutureTask);
        }
        for (Future<Result> future : futures) {
            Result result = future.get();
            System.out.println(result.getMsgCode());
        }
        futures.clear();
    }

    /**
     * 测试拒绝策略
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void testPolicy() throws InterruptedException, ExecutionException {
        List<FutureTask> futureTasks = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            FutureTask<String> stringFutureTask = new FutureTask<String>(new TestCallable("第" + i + "组任务"));
            executorsRun.execute(stringFutureTask);
//            executorsAbort.execute(stringFutureTask);
//            executorsDiscardOld.execute(stringFutureTask);
//            executorsDiscard.execute(stringFutureTask);
            futureTasks.add(stringFutureTask);
        }
        for (FutureTask futureTask : futureTasks) {
            System.out.println(futureTask.get().toString());
        }
        futureTasks.clear();
    }

    /**
     * 定长线程池 缓存
     *
     * @return
     */
    public static ExecutorService createFixedThreadPool(String type) {
        switch (type) {
            case "cached":
                return Executors.newCachedThreadPool();
            case "fixed":
                return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
            case "scheduled":
                return Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
            case "single":
            default:
                return Executors.newSingleThreadExecutor();

        }
    }


}

@AllArgsConstructor
class TestCallable implements Callable {
    private String world;

    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "  start");
        TimeUnit.SECONDS.sleep(2);
        System.out.println(Thread.currentThread().getName() + "  end");
        return world;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Task implements Callable<Result> {
    private String taskName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date taskTime;
    private Object taskResult;

    @Override
    public Result call() throws Exception {
        Thread.sleep(1000);
        TimeUnit.SECONDS.sleep(2);
        System.out.println(Thread.currentThread().getName() + "执行了任务");
        return new Result(taskName, taskTime.toString(), JSONObject.toJSON(taskResult));
    }
}

@Data
@AllArgsConstructor
class Result {
    private String msgCode;
    private String meg;
    private Object data;
}